package com.wsoft.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wsoft.constant.redis.RedisKeyConstant;
import com.wsoft.core.annotation.GetRedisCache;
import com.wsoft.core.annotation.InitRedisCache;
import com.wsoft.core.exception.Asserts;
import com.wsoft.core.service.RedisService;
import com.wsoft.core.utils.LoginUserUtil;
import com.wsoft.entity.BaseEntity;
import com.wsoft.enums.ConfigInitEnum;
import com.wsoft.system.dto.TsConfigInfoDto;
import com.wsoft.system.entity.SysOrganizationEntity;
import com.wsoft.system.entity.TsConfigEntity;
import com.wsoft.system.entity.TsConfigInfoEntity;
import com.wsoft.system.mapper.TsConfigInfoMapper;
import com.wsoft.system.query.config.*;
import com.wsoft.system.service.ISysOrganizationService;
import com.wsoft.system.service.ITsConfigInfoService;
import com.wsoft.system.service.ITsConfigService;
import com.wsoft.vo.LoginUserVO;
import com.wsoft.vo.config.ConfigRespVO;
import com.wsoft.vo.config.MemberConfigVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 个人配置系统信息表 服务实现类
 * </p>
 *
 * @author kyle
 * @since 2024年09月01日 08:52:31
 */
@Service
public class TsConfigInfoServiceImpl extends ServiceImpl<TsConfigInfoMapper, TsConfigInfoEntity> implements ITsConfigInfoService {

    @Resource
    private RedisService redisService;
    @Autowired
    private ITsConfigService configService;
    @Resource
    private ISysOrganizationService organizationService;




    @Override
    @InitRedisCache(type = RedisKeyConstant.CONFIG_CACHE_CODE,
            value ="code")
    public boolean insert(TsConfigInfoDto dto) {
        TsConfigInfoEntity entity = Convert.convert(TsConfigInfoEntity.class, dto);
        // 校验用户、组织是否重复
        QueryWrapper<TsConfigInfoEntity> query = new QueryWrapper<>();
        query.lambda().eq(TsConfigInfoEntity::getCode, entity.getCode());

        if (entity.getMemberId() != null) {
            query.lambda().eq(TsConfigInfoEntity::getMemberId, entity.getMemberId());
        }

        if (entity.getOrgId() != null) {
            query.lambda().eq(TsConfigInfoEntity::getOrgId, entity.getOrgId());
        }

        if (count(query) > 0) {
            Asserts.fail("[ts.code.exist]");
        }

        boolean b = save(entity);
        if (b) {
            if (entity.getMemberId() != null) {
                redisService.del(RedisKeyConstant.CONFIG_INFO_MEMBER + entity.getMemberId());
            }
            if (entity.getOrgId() != null) {
                redisService.del(RedisKeyConstant.CONFIG_INFO_ORG + entity.getOrgId());
            }
        }
        return b;
    }

    @Override
    public void insertOrUpdateConfigInfo(TsConfigInfoQuery query) {
        LoginUserVO loginUserVO = LoginUserUtil.getUserInfo().getLoginUserVO();
        TsConfigInfoEntity entity = Convert.convert(TsConfigInfoEntity.class, query);
        QueryWrapper<TsConfigInfoEntity> configQuery = new QueryWrapper<>();
        configQuery.lambda().eq(TsConfigInfoEntity::getMemberId, loginUserVO.getId())
                    .eq(TsConfigInfoEntity::getCode, entity.getCode());
        if (count(configQuery)>0){
            update(entity,configQuery);
        }
        else {
            entity.setMemberId(loginUserVO.getId());
            save(entity);
        }
        redisService.del(RedisKeyConstant.CONFIG_INFO_MEMBER + loginUserVO.getId());
    }

    @Override
    @InitRedisCache(types = {RedisKeyConstant.CONFIG_INFO,RedisKeyConstant.CONFIG_CACHE_CODE},
            values ={ "id","code"})
    public boolean update(TsConfigInfoDto dto) {
        TsConfigInfoEntity entity = Convert.convert(TsConfigInfoEntity.class, dto);
        TsConfigInfoEntity configInfo = getConfigInfo(entity.getId());
        QueryWrapper<TsConfigInfoEntity> query = new QueryWrapper<>();
        query.lambda().eq(TsConfigInfoEntity::getCode, entity.getCode());

        if (entity.getMemberId() != null) {
            query.lambda().eq(TsConfigInfoEntity::getMemberId, entity.getMemberId())
                    .ne(BaseEntity::getId, entity.getId());;
        }

        if (entity.getOrgId() != null) {
            query.lambda().eq(TsConfigInfoEntity::getOrgId, entity.getOrgId())
                    .ne(BaseEntity::getId, entity.getId());
        }

        if (count(query) > 0) {
            Asserts.fail("[ts.code.exist]");
        }
        boolean b = updateById(entity);
        if (b) {
            if (entity.getMemberId() != null) {
                redisService.del(RedisKeyConstant.CONFIG_INFO_MEMBER + configInfo.getMemberId());
            }
            if (entity.getOrgId() != null) {
                redisService.del(RedisKeyConstant.CONFIG_INFO_ORG + configInfo.getOrgId());
            }
        }
        return b;
    }

    @Override
    @InitRedisCache(type = RedisKeyConstant.CONFIG_INFO,
    value = RedisKeyConstant.REDIS_SELF)
    public boolean delete(Long id) {
        TsConfigInfoEntity configInfo = getConfigInfo(id);
        boolean b = removeById(id);
        if (b){
            if (configInfo.getOrgId()!=null){
                redisService.del(RedisKeyConstant.CONFIG_INFO_CODE+configInfo.getCode());
                redisService.del(RedisKeyConstant.CONFIG_INFO_ORG+configInfo.getOrgId());
            }
            if (configInfo.getMemberId()!=null){
                redisService.del(RedisKeyConstant.CONFIG_INFO_CODE+configInfo.getCode());
                redisService.del(RedisKeyConstant.CONFIG_INFO_MEMBER+configInfo.getMemberId());
            }
        }
        return b;
    }

    @Override
    public boolean recover(String code) {
        QueryWrapper<TsConfigInfoEntity> query =  new QueryWrapper<>();
        query.lambda().eq(TsConfigInfoEntity::getCode,code)
                .eq(TsConfigInfoEntity::getMemberId,LoginUserUtil.getUserInfo().getLoginUserVO().getId());
        return remove(query);
    }

    @Override
    public boolean recoverAll() {
        QueryWrapper<TsConfigInfoEntity> query =  new QueryWrapper<>();
                query.lambda().eq(TsConfigInfoEntity::getMemberId,LoginUserUtil.getUserInfo().getLoginUserVO().getId());
        return remove(query);
    }

    @Override
    @GetRedisCache(type = RedisKeyConstant.CONFIG_INFO,
    value = RedisKeyConstant.REDIS_SELF)
    public TsConfigInfoEntity getConfigInfo(Long id) {
        return getById(id);
    }

    @Override
    @GetRedisCache(type = RedisKeyConstant.CONFIG_INFO_CODE,
    value = RedisKeyConstant.REDIS_SELF)
    public List<TsConfigInfoEntity> getConfigInfoByCode(String code) {
        QueryWrapper<TsConfigInfoEntity> query =  new QueryWrapper<>();
        query.lambda().eq(TsConfigInfoEntity::getCode,code);
        return list(query);
    }

    @Override
    public List<TsConfigInfoEntity> getConfigInfoByOrg(ConfigInfoOrgQuery query) {
        QueryWrapper<TsConfigInfoEntity> queryWrapper = new QueryWrapper<>();
        if (StrUtil.isNotBlank(query.getCode())) {
            queryWrapper.lambda().eq(TsConfigInfoEntity::getCode, query.getCode());
        }
        if (StrUtil.isNotBlank(query.getName())) {
            queryWrapper.lambda().like(TsConfigInfoEntity::getName, query.getName());
        }
        queryWrapper.lambda().eq(TsConfigInfoEntity::getOrgId, query.getOrgId());
        return list(queryWrapper);
    }

    @Override
    @GetRedisCache(type= RedisKeyConstant.CONFIG_INFO_ORG,
    value = RedisKeyConstant.REDIS_SELF)
    public List<TsConfigInfoEntity> getConfigInfoByOrgId(Long orgId ) {
        QueryWrapper<TsConfigInfoEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TsConfigInfoEntity::getOrgId, orgId);
        return list(queryWrapper);
    }

    @Override
    public List<TsConfigInfoEntity> getConfigInfoByMember(ConfigInfoMemberQuery query) {
        QueryWrapper<TsConfigInfoEntity> queryWrapper = new QueryWrapper<>();
        if (StrUtil.isNotBlank(query.getCode())) {
            queryWrapper.lambda().eq(TsConfigInfoEntity::getCode, query.getCode());
        }
        if (StrUtil.isNotBlank(query.getName())) {
            queryWrapper.lambda().like(TsConfigInfoEntity::getName, query.getName());
        }
        queryWrapper.lambda().eq(TsConfigInfoEntity::getMemberId, query.getMemberId());
        return list(queryWrapper);
    }

    @Override
    @GetRedisCache(type= RedisKeyConstant.CONFIG_INFO_MEMBER,
    value = RedisKeyConstant.REDIS_SELF)
    public List<TsConfigInfoEntity> getConfigInfoByMemberId(Long memberId) {
        QueryWrapper<TsConfigInfoEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TsConfigInfoEntity::getMemberId, memberId);
        return list(queryWrapper);
    }

    @Override
    public ConfigRespVO getConfigByCode(Long memberId, Long orgId, String code) {
        if (StrUtil.isBlank(code)){
            Asserts.fail("[ts.code.not.empty]");
        }
        TsConfigEntity configEntity = configService.getConfigByCode(code);
        if (ObjUtil.isEmpty(configEntity)){
            Asserts.fail("[config.error.empty]");
        }
        if (configEntity.getIsOrgInit().equals(ConfigInitEnum.DISABLE.getValue()) &&configEntity.getIsMemberInit().equals(ConfigInitEnum.DISABLE.getValue())){
            return Convert.convert(ConfigRespVO.class,configEntity);
        }
        if (configEntity.getIsMemberInit().equals(ConfigInitEnum.DISABLE.getValue())){
            // 加载组织链环境配置
            if (orgId != null) {
                TsConfigInfoEntity lookupOrgConfig = lookupOrgConfig(orgId,code);
                if (lookupOrgConfig != null) {
                    return Convert.convert(ConfigRespVO.class, lookupOrgConfig);
                }
            }
        }
        List<TsConfigInfoEntity> list = getConfigInfoByMemberId(memberId);
        List<TsConfigInfoEntity> collect = list.stream().filter(item -> item.getCode().equals(code)).collect(Collectors.toList());
        if (configEntity.getIsOrgInit().equals(ConfigInitEnum.DISABLE.getValue())){
            if (!collect.isEmpty()) {
                return Convert.convert(ConfigRespVO.class, collect.get(0));
            }
        }
        if (configEntity.getIsOrgInit().equals(ConfigInitEnum.ENABLE.getValue()) &&configEntity.getIsMemberInit().equals(ConfigInitEnum.ENABLE.getValue())){
            if (memberId!=null){
                if (!collect.isEmpty()) {
                    return Convert.convert(ConfigRespVO.class, collect.get(0));
                }
                else {
                    if (orgId!=null){
                        // 加载组织链环境配置
                        TsConfigInfoEntity lookupOrgConfig = lookupOrgConfig(orgId,code);
                        if (lookupOrgConfig != null) {
                            return Convert.convert(ConfigRespVO.class, lookupOrgConfig);
                        }
                     }
                    }
                }
            }
        return Convert.convert(ConfigRespVO.class,configEntity);
    }

    @Override
    public List<MemberConfigVO> getConfigurableByMember(PersonConfigInfoQuery query) {
        Long memberId = LoginUserUtil.getUserInfo().getLoginUserVO().getId();
        ConfigListQuery listQuery = new ConfigListQuery();
        listQuery.setIsMemberInit(1);
        //个人可配置的环境配置
        List<TsConfigEntity> configurableEntities = configService.listConfig(listQuery);
        //个人已配置的环境配置
        List<TsConfigInfoEntity> list = getConfigInfoByMemberId(memberId);
        // 将已修改的配置转换为 Map，方便快速查找
        Map<String, TsConfigInfoEntity> modifiedConfigMap = list.stream()
                .collect(Collectors.toMap(TsConfigInfoEntity::getCode, e -> e));

        // 构建返回结果
        List<MemberConfigVO> result = new ArrayList<>();
        for (TsConfigEntity configEntity : configurableEntities) {
            MemberConfigVO convert = Convert.convert(MemberConfigVO.class, configEntity);
            // 检查当前用户是否修改过该配置
            if (modifiedConfigMap.containsKey(configEntity.getCode())) {
                TsConfigInfoEntity modifiedConfig = modifiedConfigMap.get(configEntity.getCode());
                convert = Convert.convert(MemberConfigVO.class, modifiedConfig);
                convert.setDefaulted(false); // 非默认
            } else {
                convert.setDefaulted(true);// 默认
            }
            result.add(convert);
        }
        // 根据 query 参数筛选结果
        if (query != null) {
            result = result.stream()
                    .filter(item -> {
                        boolean match = true;

                        // 根据 code 筛选
                        if (StrUtil.isNotBlank(query.getCode())) {
                            match = match && item.getCode().contains(query.getCode());
                        }

                        // 根据 name 筛选
                        if (StrUtil.isNotBlank(query.getName())) {
                            match = match && item.getName().contains(query.getName());
                        }

                        // 根据 defaulted 筛选
                        if (query.getDefaulted()!=null) {
                            match = match && item.getDefaulted().equals(query.getDefaulted());
                        }

                        return match;
                    })
                    .collect(Collectors.toList());
        }
        return result;
    }

    @Override
    public ConfigRespVO getDetail(String code) {
        LoginUserVO loginUserVO = LoginUserUtil.getUserInfo().getLoginUserVO();
        return getConfigByCode(loginUserVO.getId(),loginUserVO.getLoginOrgId(),code);
    }


    private TsConfigInfoEntity lookupOrgConfig(Long curOrgId,String code) {
        List<SysOrganizationEntity> allOrgWithCache = organizationService.listAllOrgWithCache();
        if (CollUtil.isEmpty(allOrgWithCache)) {
            Asserts.fail("[cache.error.empty.allOrgWithCache]");
        }

        Map<Long, SysOrganizationEntity> orgParentMap = allOrgWithCache.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
        // 尝试循环加载组织配置
        do {
            // 加载当前组织的环境变量
            List<TsConfigInfoEntity> list = getConfigInfoByOrgId(curOrgId);
            List<TsConfigInfoEntity> collect = list.stream().filter(item -> item.getCode().equals(code)).collect(Collectors.toList());
            if (!collect.isEmpty()) {
                 return collect.get(0);
            }
            // 否则继续往上一级查找
            curOrgId = orgParentMap.get(curOrgId).getPaId();

        } while (curOrgId != null && curOrgId.longValue() != 0);

        return null;
    }
}
